#include "block_log.h"
#include <sys/stat.h>
#include "WorkerThreadPool.h"

// 互斥锁初始化
std::mutex BlockLog::m_mutex;

BlockLog::BlockLog() : m_split_lines(0),
                       m_log_buf_size(0),
                       m_count(0),
                       m_today(0),
                       m_fp(nullptr),
                       m_buf(nullptr),
                       m_log_queue(nullptr),
                       m_is_async(false),
                       m_close_log(0) {}

BlockLog::~BlockLog()
{
    if (m_fp)
    {
        fclose(m_fp);
        m_fp = nullptr;
    }
    if (m_buf)
    {
        delete[] m_buf;
        m_buf = nullptr;
    }
    if (m_log_queue)
    {
        delete m_log_queue;
        m_log_queue = nullptr;
    }
}

BlockLog *BlockLog::getInstance()
{
    static BlockLog m_instance;
    return &m_instance;
}

bool BlockLog::init(const char *file_name, int close_log, int log_buf_size, int split_lines, int max_queue_size)
{
    m_close_log = close_log;
    m_log_buf_size = log_buf_size;
    m_buf = new char[m_log_buf_size];
    memset(m_buf, '\0', m_log_buf_size);
    m_split_lines = split_lines;

    // 提取目录和文件名
    const char *p = strrchr(file_name, '/');
    char log_full_name[256] = {0};
    if (p == nullptr)
    {
        // 没有目录就使用当前目录
        snprintf(log_full_name, 255, "%s", file_name);
        dir_name = ".";
        log_name = file_name;
    }
    else
    {
        // 提取目录和文件名
        strncpy(log_full_name, file_name, p - file_name);
        dir_name = std::string(file_name, p - file_name);
        log_name = p + 1;
    }
    // 获取当前日期
    time_t t = time(nullptr);
    struct tm *sys_tm = localtime(&t);
    struct tm my_tm = *sys_tm;
    m_today = my_tm.tm_mday;

    // 创建完整日志文件名
    char time_str[16] = {0};
    snprintf(time_str, 15, "%d_%02d_%02d",
             my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday);

    if (!dir_name.empty())
    {
        // 确保目录存在
        if (access(dir_name.c_str(), F_OK))
        {
            mkdir(dir_name.c_str(), 0777);
        }
    }

    // 打开日志文件
    if (m_close_log == 0)
    {
        m_fp = fopen(log_full_name, "a");
        if (m_fp == nullptr)
        {
            return false;
        }
    }

    // 异步模式初始化
    if (max_queue_size > 0)
    {
        m_is_async = true;
        m_log_queue = new block_queue<std::string>(max_queue_size);
        // 正确提交成员函数到线程池
        WorkerThreadPool::getInstance()->submitTask(
            [this]()
            {
                this->flush_log_thread(this);
            });
    }
    return true;
}

void BlockLog::write_log(int level, const char *format, ...) {
    if (m_close_log) return;

    // 获取当前时间
    struct timeval now = {0, 0};
    gettimeofday(&now, nullptr);
    time_t t = now.tv_sec;
    struct tm *sys_tm = localtime(&t);
    struct tm my_tm = *sys_tm;
    
    // 检查是否需要创建新文件
    if (m_today != my_tm.tm_mday || (m_count > 0 && m_count % m_split_lines == 0)) {
        char new_log[256] = {0};
        fflush(m_fp);
        fclose(m_fp);
        
        char tail[16] = {0};
        snprintf(tail, 16, "%d_%02d_%02d", 
                 sys_tm->tm_year + 1900, sys_tm->tm_mon + 1, sys_tm->tm_mday);
        
        if (m_today != my_tm.tm_mday) {
            // 新的一天
            snprintf(new_log, 255, "%s/%s_%s", dir_name.c_str(), log_name.c_str(), tail);
            m_today = my_tm.tm_mday;
            m_count = 0;
        } else {
            // 同一天但超过行数限制
            snprintf(new_log, 255, "%s/%s_%s.%lld", dir_name.c_str(), log_name.c_str(), tail, m_count / m_split_lines);
        }
        
        m_fp = fopen(new_log, "a");
    }
    
    // 格式化日志头
    char type_str[16] = {0};
    switch(level) {
        case 0: strcpy(type_str, "[DEBUG]"); break;
        case 1: strcpy(type_str, "[INFO]"); break;
        case 2: strcpy(type_str, "[WARN]"); break;
        case 3: strcpy(type_str, "[ERROR]"); break;
        default: strcpy(type_str, "[UNKNOW]"); break;
    }
    
    // 写入时间信息
    int n = snprintf(m_buf, m_log_buf_size, "%d-%02d-%02d %02d:%02d:%02d.%06ld %s ",
                     my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday,
                     my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec, now.tv_usec, type_str);
    
    // 处理可变参数
    va_list valst;
    va_start(valst, format);
    int m = vsnprintf(m_buf + n, m_log_buf_size - n, format, valst);
    va_end(valst);
    
    m_buf[n + m] = '\n';
    m_buf[n + m + 1] = '\0';
    
    std::string log_str = m_buf;
    m_count++;
    
    //同步/异步写入
    if (!m_is_async && !m_log_queue->full()) {//异步
        m_log_queue->push(log_str);
    } else {//同步
        std::lock_guard<std::mutex> lock(m_mutex);
        fputs(log_str.c_str(), m_fp);
    }

}

void BlockLog::mflush(void) {
    std::lock_guard<std::mutex> lock(m_mutex);
    fflush(m_fp);
}

void BlockLog::flush_log_thread(void *args) {
    BlockLog::getInstance()->async_write_log();
}

void* BlockLog::async_write_log() {
    std::string single_log;
    while (m_log_queue->pop(single_log)) {
        std::lock_guard<std::mutex> lock(m_mutex);
        fputs(single_log.c_str(), m_fp);
    }
    return nullptr;
}